package org.example.judge.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.example.judge.controller.ProblemCaseController;
import org.example.judge.mapper.ProblemMapper;
import org.example.judge.oj.JudgeResult;
import org.example.judge.service.ProblemCaseService;
import org.example.judge.service.ProblemService;
import org.example.judge.service.ProblemTagService;
import org.example.judge.service.SubmitService;
import org.example.judge_common.entity.PageResult;
import org.example.judge_common.entity.RequestParams;
import org.example.judge_common.entity.RequestProblemParams;
import org.example.judge_common.entity.ResponseResult;
import org.example.judge_common.util.IdWorker;
import org.example.judge_common.util.MyUtils;
import org.example.judge_pojo.Problem;
import org.example.judge_pojo.ProblemCase;
import org.example.judge_pojo.ProblemTag;
import org.example.judge_pojo.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

@Service("ProblemServiceImpl")
@Transactional
@Slf4j
public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> implements ProblemService {


    @Qualifier("ProblemCaseServiceImpl")
    @Autowired
    private ProblemCaseService problemCaseService;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private ProblemCaseController problemCaseController;
    @Autowired
    private RedisTemplate redisTemplate;

    @Qualifier("SubmitServiceImpl")
    @Autowired
    private SubmitService submitService;
    @Qualifier("ProblemTagServiceImpl")
    @Autowired
    private ProblemTagService problemTagService;
    @Override
    public boolean save(Problem entity) {
        entity.setId(idWorker.nextId().toString());
        if(entity.getAuth()!=0&&entity.getAuth()!=2)entity.setAuth(1);  //默认为私密的
        //设置默认时间，内存，栈大小限制
        if(entity.getMemoryLimit()==null||entity.getMemoryLimit()==0)entity.setMemoryLimit(512);
        if(entity.getStackLimit()==null||entity.getStackLimit()==0)entity.setStackLimit(128);
        if(entity.getTimeLimit()==null||entity.getTimeLimit()==0)entity.setTimeLimit(1000);
        entity.setUpdateTime(new Date());
        entity.setCode(this.getMaxCode()+1);
        if(entity.getTags()!=null&&entity.getTags().size()>0){  //添加标签
            for (Tag tag : entity.getTags()) {

                ProblemTag problemTag = new ProblemTag();
                problemTag.setId(idWorker.nextId().toString());
                problemTag.setProblemId(entity.getId());
                problemTag.setTagId(tag.getId());
                problemTagService.save(problemTag);
            }
        }
        return super.save(entity);
    }

    private Integer getMaxCode(){
        return super.baseMapper.getMaxCode();
    }

    @Override
    public boolean removeById(Serializable id) {

        redisTemplate.opsForValue().set(id,null);
        //删除标签
        problemTagService.remove(new QueryWrapper<ProblemTag>().eq("problem_id",id));
        //先删除题目的所有测试用例
//        ResponseResult responseResult = problemCaseController.listByProblemId(id.toString());
        List<ProblemCase> data = problemCaseService.listByProblemId(id.toString());
        // 测试数据列表
        for (ProblemCase datum : data) {
            problemCaseController.deleteById(datum.getId(),null);  //删除所有测试数据
        }
        return super.removeById(id);
    }

    @Override
    public boolean updateById(Problem entity) {
        entity.setUpdateTime(new Date());
        redisTemplate.opsForValue().set(entity.getId(),null);
        //先删除标签
        problemTagService.remove(new QueryWrapper<ProblemTag>().eq("problem_id",entity.getId()));
        //再添加标签
        if(entity.getTags()!=null&&entity.getTags().size()>0){  //修改标签
            for (Tag tag : entity.getTags()) {
                ProblemTag problemTag = new ProblemTag();
                problemTag.setId(idWorker.nextId().toString());
                problemTag.setProblemId(entity.getId());
                problemTag.setTagId(tag.getId());
                problemTagService.save(problemTag);
            }
        }
        return super.updateById(entity);
    }

    @Override
    public Problem getById(Serializable id) {
        //率先访问缓存
        Object o = redisTemplate.opsForValue().get(id);
        Problem byId = null;
        if(o!=null)byId = JSON.parseObject(((String) o),Problem.class);
        if(byId!=null){
            return byId;
        }
        byId = super.getById(id);
        if(byId==null)return null;
        //通过率
        byId.setSubmitSum(submitService.getSumByProblem(byId.getId()));
        byId.setSubmited(submitService.getAccessSumByProblem(byId.getId()));
        if(byId!=null&&byId.getAuth()==2){ //处于比赛中的题目应当加入缓存中,30分钟
            redisTemplate.opsForValue().set(id,JSON.toJSONString(byId),30, TimeUnit.MINUTES);
        }
        return byId;

    }

    @Override
    public PageResult<Problem> search(RequestProblemParams params) {
        if(MyUtils.isEmpty(params.getField())||"null".equals(params.getField())){ //默认排序字段
            params.setField("code");
        }
        if(MyUtils.isEmpty(params.getOrder())||"null".equals(params.getOrder())){   //默认排序方式
            params.setOrder("desc");
        }
        //判断是否合法
        if(params.getDifficulty()!=null&&params.getDifficulty()<0&&params.getDifficulty()>5){
            params.setDifficulty(null);
        }
        //判断是否合法
        if(params.getAuth()!=null&&params.getAuth()<1&&params.getAuth()>2){
            params.setAuth(null);
        }
        QueryWrapper<Problem> queryWap = new QueryWrapper<>();

        //字段模糊匹配
        if(MyUtils.isNotEmpty(params.getKey())){
            queryWap.and(new Consumer<QueryWrapper<Problem>>() { //隔离or条件
                @Override
                public void accept(QueryWrapper<Problem> problemQueryWrapper) {
                    problemQueryWrapper.like("title",params.getKey()).or().like("description",params.getKey());
                }
            });

        }

        //困难星数
        if(params.getDifficulty()!=null)queryWap.eq("difficulty",params.getDifficulty());
        //权限
        if(params.getAuth()!=null)queryWap.eq("auth",params.getAuth());

        //标签
        if(params.getTags()!=null&&params.getTags().size()>0){  //标签查找
            //已完成
//            log.error("未完成功能-按照标签分类查询题目");
            QueryWrapper<ProblemTag> queryTag = new QueryWrapper<>();
            queryTag.in("tag_id",params.getTags());
            List<ProblemTag> list = problemTagService.list(queryTag);  //根据标签获取题目ids

            //判断是否存在
            if (list!=null&&list.size()>0) {
                //抽取出题目id
                List<String> ids = new ArrayList<>(list.size());
                for (ProblemTag problemTag : list) {
                    ids.add(problemTag.getProblemId());
                }

                //将题目id传入查询参数中
                queryWap.in("id",ids);
            }else{ //无数据
                queryWap.in("id","-1");
            }

        }else if(params.getAccept()!=null&&params.getAccept()==1){
            //查询未通过的题目
            List<String> ids = submitService.getNoAcceept(params.getUserId());
//        System.out.println(ids);
            if(ids!=null&&ids.size()>0)queryWap.in("id",ids);
                //无数据
            else queryWap.in("id","-1");
        }
        //排序
        queryWap.orderBy(true,"asc".equalsIgnoreCase(params.getOrder()),params.getField());

        //设置分页
        PageHelper.startPage(params.getPage(), params.getSize(),false);
        List<Problem> problems = this.baseMapper.selectList(queryWap);
        //求数据条数
        Integer count = this.baseMapper.selectCount(queryWap);
        for (Problem problem : problems) {
            //通过率
            problem.setSubmitSum(submitService.getSumByProblem(problem.getId()));
            problem.setSubmited(submitService.getAccessSumByProblem(problem.getId()));
            //是否提交
            if(MyUtils.isNotEmpty(params.getUserId())){
                //通过
                if (submitService.getSumbitSum(problem.getId(),params.getUserId(), JudgeResult.ACCEPTED)>0) {
                    problem.setStatus(0);
                }else if(submitService.getSumbitSum(problem.getId(),params.getUserId(),null)>0){
                    //未通过
                    problem.setStatus(1);
                }


//                queryWap.in("id",ids);
            }
            //标签
            List<Tag> tags = problemTagService.listTags(problem.getId());
            problem.setTags(tags);

        }
        return new PageResult<Problem>(count.longValue(),problems);
    }
}
